import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * ClassName:Tetris
 * Description:
 * author: jiuyang
 * DateTime: 2024/8/7 下午3:37
 */
public class Tetris extends JPanel {

    public static BufferedImage I;
    public static BufferedImage J;
    public static BufferedImage L;
    public static BufferedImage O;
    public static BufferedImage S;
    public static BufferedImage T;
    public static BufferedImage Z;
    public static BufferedImage backImage;

    private Tetromino currentOne = Tetromino.randomOne();
    private Tetromino nextOne = Tetromino.randomOne();

    private Cell[][] wall = new Cell[18][9];

    private static final int CELL_SIZE = 48;

    int[] scores_pool = {0, 1, 2, 5, 10};
    private int totalScore;
    private int totalLine;


    public static final int PLAYING = 0;
    public static final int PAUSE = 1;
    public static final int GAMEOVER = 2;

    private int game_state;
    String[] show_state = {"P[pause]", "C[continue]", "S[replay]"};


    static {
        try {
            I = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\I.png"));
            J = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\J.png"));
            L = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\L.png"));
            O = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\O.png"));
            S = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\S.png"));
            T = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\T.png"));
            Z = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\Z.png"));
            backImage = ImageIO.read(new File("D:\\TJY\\代码\\Game\\Tetris\\images\\background.png"));

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {

        JFrame jFrame = new JFrame("俄罗斯方块");
        Tetris tetris = new Tetris();
        jFrame.add(tetris);
        // 设置可见
        jFrame.setVisible(true);
        // 窗口大小
        jFrame.setSize(810, 940);
        // 窗口居中
        jFrame.setLocationRelativeTo(null);
        // 窗口关闭程序中止
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        tetris.start();
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(backImage, 0, 0, null);
        g.translate(22, 15);
        // 绘制游戏主区域
        paintWall(g);
        // 绘制下落方块
        paintCurrentOne(g);
        // 绘制下一个方块
        paintNextOnr(g);
        // 绘制游戏得分
        paintScore(g);
        // 绘制游戏状态
        paintState(g);
    }

    public void start(){
        game_state = PLAYING;
        KeyListener k = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int code = e.getKeyCode();
                switch (code){
                    case KeyEvent.VK_DOWN -> sortDropAction();
                    case KeyEvent.VK_LEFT -> leftMoveAction();
                    case KeyEvent.VK_RIGHT -> rightMoveAction();
                    case KeyEvent.VK_UP -> rotateRightAction();
                    case KeyEvent.VK_SPACE -> handDropAction();
                    case KeyEvent.VK_P -> {
                        if (game_state==PLAYING){
                            game_state = PAUSE;
                        }
                    }
                    case KeyEvent.VK_C -> {
                        if (game_state==PAUSE){
                            game_state = PLAYING;
                        }
                    }
                    case KeyEvent.VK_S -> {
                        game_state = PLAYING;
                        wall = new Cell[18][9];
                        currentOne =  Tetromino.randomOne();
                        nextOne = Tetromino.randomOne();
                        totalLine = 0;
                        totalScore = 0;
                    }
                }
                repaint();
            }
        };

        this.addKeyListener(k);
        this.requestFocus();

        //四方格自动下落
        while (true){
            if (game_state==PLAYING){
                try {
                    Thread.sleep(500);
                }catch (Exception e){
                    e.printStackTrace();
                }
                if(canDrop()){
                    currentOne.softDrop();
                }else {
                    landToWall();
                    destroyLine();
                    if (isGameOver()){
                        game_state = GAMEOVER;
                    }else {
                        currentOne = nextOne;
                        nextOne = Tetromino.randomOne();
                    }
                }

            }
            repaint();
        }

    }




    // 创建顺时针旋转
    public void rotateRightAction(){
        currentOne.rotateRight();
        //判断是否越界或者重合
        if (outOfBounds()||conincide()){
            currentOne.rotateLeft();
        }
    }

    // 瞬间下落
    public void handDropAction(){
        while (true){
            if (canDrop()) {
                currentOne.softDrop();
            }else {
                break;
            }
        }
        landToWall();
        destroyLine();
        if (isGameOver()){
            game_state = GAMEOVER;
        }else {
            currentOne = nextOne;
            nextOne = Tetromino.randomOne();
        }
    }

    // 按键一次四方格下降一格
    public void sortDropAction(){
        if (canDrop()){
            currentOne.softDrop();
        }else{
            landToWall();
            destroyLine();
            if (isGameOver()){
                game_state = GAMEOVER;
            }else {
                currentOne = nextOne;
                nextOne = Tetromino.randomOne();
            }
        }
    }

    // 将四方格嵌入墙中
    public void landToWall(){
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            wall[row][col] = cell;
        }
    }

    // 判断四方格能否下落
    public boolean canDrop(){
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int col = cell.getCol();
            int row = cell.getRow();
            if (row==wall.length-1){
                return false;
            }else if (wall[row+1][col] !=null){
                return false;
            }
        }
        return true;
    }

    // 消除一行
    public void destroyLine(){
        int line = 0;
        Cell[] cells =  currentOne.cells;
        for (Cell cell : cells) {
            int row = cell.getRow();
            // 判断当前是否满行
            if (isFullLine(row)) {
                line++;
                for (int i = row; i > 0; i--) {
                    System.arraycopy(wall[i-1],0,wall[i],0,wall[0].length);
                }
                wall[0] = new Cell[9];
            }
        }
        // 在分数池中获取分数，累加到总分中
        totalScore+=scores_pool[line];
        totalLine+=line;
    }

    // 判断当前行是否已满
    public boolean isFullLine(int row) {
        Cell[] cells = wall[row];
        for (Cell cell : cells) {
            if (cell == null) {
                return false;
            }
        }
        return true;
    }

    // 判断游戏是否结束
    public boolean isGameOver(){
        Cell[] cells = nextOne.cells;
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            if (wall[row][col]!=null){
                return true;
            }
        }
        return false;
    }

    private void paintState(Graphics g) {

        if (game_state == PLAYING) {
            g.drawString(show_state[0], 500, 660);
        } else if (game_state == PAUSE) {
            g.drawString(show_state[1], 500, 660);
        } else if (game_state == GAMEOVER) {
            g.drawString(show_state[2], 500, 660);
            g.setColor(Color.red);
            g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));
            g.drawString("GAME OVER!", 30, 400);
        }

    }

    private void paintScore(Graphics g) {
        g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));
        g.drawString("SCORES: " + totalScore, 500, 248);
        g.drawString("LINES: " + totalLine, 500, 430);
    }

    private void paintNextOnr(Graphics g) {
        Cell[] cells = nextOne.cells;
        for (Cell cell : cells) {
            int x = cell.getCol() * CELL_SIZE + 370;
            int y = cell.getRow() * CELL_SIZE + 25;
            g.drawImage(cell.getBufferedImage(), x, y, null);
        }
    }

    private void paintCurrentOne(Graphics g) {
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int x = cell.getCol() * CELL_SIZE;
            int y = cell.getRow() * CELL_SIZE;
            g.drawImage(cell.getBufferedImage(), x, y, null);
        }
    }

    private void paintWall(Graphics g) {
        for (int i = 0; i < wall.length; i++) {
            for (int j = 0; j < wall[i].length; j++) {
                int x = j * CELL_SIZE;
                int y = i * CELL_SIZE;

                Cell cell = wall[i][j];
                if (cell == null) {
                    g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
                } else {
                    g.drawImage(cell.getBufferedImage(), x, y, null);
                }
            }
        }
    }

    // 判断方块是否出界
    public boolean outOfBounds() {
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int col = cell.getCol();
            int row = cell.getRow();
            if (col<0||col>8||row<0||row>18) return true;
        }
        return false;
    }

    // 判断方块是否重合
    public boolean conincide() {
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            if (wall[row][col] != null)
                return true;
        }
        return false;
    }

    // 按键一次四方格左移一次
    public void leftMoveAction() {
        currentOne.moveLeft();
        if (outOfBounds() || conincide()) {
            currentOne.moveRight();
        }
        repaint();
    }

    // 按键一次四方格右移一次
    public void rightMoveAction() {
        currentOne.moveRight();
        if (outOfBounds() || conincide()) {
            currentOne.moveLeft();
        }
        repaint();
    }





}
